﻿from django.utils.deprecation import MiddlewareMixin
import jwt

from django.conf import settings

from rest_framework.authentication import BaseAuthentication, get_authorization_header #问题 这几个模块是干什么的呢？
from rest_framework import exceptions

from django.http.response import JsonResponse

from rest_framework.status import HTTP_403_FORBIDDEN

from django.contrib.auth.models import AnonymousUser
from django.shortcuts import reverse



# 导入用户信息
from .models import OAUser
class LgoinCheckMiddleware(MiddlewareMixin):

    keyword = 'jwt'

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 对于那些不需要登录就能访问的接口，可以写在这里
        self.white_list = [reverse('oaauth:login'), reverse('staff:active_staff'), reverse('home:health_check')]

    def process_view(self, request, view_func, view_args, view_kwargs):
        # 1.如果返回None，那么和正常执行(包含执行视图、执行其他中间件的代码)
        # 2.如果返回一个HttpResponse对象，那么将不会执行视图、及之后的中间件代码

        # 如果是登录界面，那么直接返回None，正常执行即可。否则，则需要进行验证
        if request.path in self.white_list or request.path.startswith(settings.MEDIA_URL):
            request.user = AnonymousUser()
            request.auth = None
            return None

        try:
            # 从请求头中获取Authorization
            # 把Authorization字段切割成两段(以空格为分隔符，按理存在两个字段：["JWT", "401f7ac837da42b97f613d789819ff93537bee6a"]
            auth = get_authorization_header(request).split()

            # auth字段为空｜或者auth的第一个字段(按理是JWT)不等于JWT的小写形式，那么则认为没有返回JWT，系统则返回NONE
            if not auth or auth[0].lower() != self.keyword.lower().encode():
                print(auth)
                raise exceptions.ValidationError("请传入JWT！")

            if len(auth) == 1:  # 只分割出1个内容，不对！
                msg = ('没有提供JWT Token!')
                raise exceptions.AuthenticationFailed(msg)
            elif len(auth) > 2:  # 分割出>2个内容，说明存在多个空格。JWT格式错误
                msg = ('JWT Token不可用!应该提供一个空格。')
                raise exceptions.AuthenticationFailed(msg)

            try:
                jwt_token = auth[1]  # 获取JWT的实际Token字符串
                jwt_info = jwt.decode(jwt_token, settings.SECRET_KEY, algorithms="HS256")  # 对JWT的Token进行解码。如果在解码的时候，/
                # 发现有"exp"字段(请参照函数"generate_jwt"中的jwt.encode)，而且exp已经过期，则会报错ExpiredSignatureError(参考下方except部分)

                userid = jwt_info.get('userid')  # JWT被解码成功后(应该是一个对象)、获取其中的useid #问题(为啥需要用get)

                try:  # 对所提取出来的userid进行验证
                    user = OAUser.objects.get(pk=userid)  # 使用ORM进行查询，如果成功的话，将可以得到用户信息
                    request.user = user
                    request.auth = jwt_token
                    # return (user, None)  # 返回元组：用户信息 + None
                except:  # 如果没有查询到此用户
                    msg = "用户不存在!"
                    raise exceptions.AuthenticationFailed(msg)

            except jwt.ExpiredSignatureError:
                msg = ('Token已经过期！')
                raise exceptions.AuthenticationFailed(msg)

        except Exception as e:
            print(e)
            return JsonResponse(data={'detail': "请先登录！"}, status = HTTP_403_FORBIDDEN)

